home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Internet software / NewsWatcher / NW Source / Source / help.c < prev    next >
Text File  |  1997-01-09  |  28KB  |  1,124 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.     help.c
  4.  
  5.     This module handles the help topic windows. It also exports some
  6.     utility functions for displaying help balloons.
  7.     
  8.     Copyright © 1994-1997, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include "Icons.h"
  13. #include "string.h"
  14. #include "ctype.h"
  15.  
  16. #include "glob.h"
  17. #include "help.h"
  18. #include "menus.h"
  19. #include "resutil.h"
  20. #include "wind.h"
  21. #include "dialog.h"
  22. #include "newswatcher.h"
  23. #include "memutil.h"
  24. #include "windutil.h"
  25. #include "key.h"
  26. #include "iconutil.h"
  27. #include "fileutil.h"
  28. #include "strutil.h"
  29. #include "sfutil.h"
  30. #include "drawutil.h"
  31. #include "print.h"
  32. #include "status.h"
  33. #include "menuutil.h"
  34.  
  35.  
  36.  
  37. #define kMinWindowWidth        299            /* minimum window width */
  38. #define kMinWindowHeight    85            /* minimum window height */
  39. #define kPanelHeight        22            /* panel height */
  40.  
  41. #define kFirstHelpMenuPictResourceID    1000    /* Resource id of first 'PICT' 
  42.                                                    resource for help topics */
  43. #define kDynamicWindowStringsResourceID    133        /* STR# resource id for dynamic window
  44.                                                    balloon help strings */
  45.  
  46. static short gNumStandardHelpMenuItems;        /* number of items in standard system
  47.                                                Help menu */
  48. static short gNumHelpTopics = 0;            /* number of items we added to
  49.                                                Help menu */
  50.  
  51. static ControlActionUPP gScrollActionUPP;
  52.  
  53.  
  54.  
  55. /*----------------------------------------------------------------------------
  56.     ShowHelpBalloon 
  57.         
  58.     Display a help balloon for a dynamic window.
  59.     
  60.     Entry:    tip = location of tip in local coordinates. If {0,0}, the middle
  61.                 of the alternateRect is used as the tip.
  62.             alternateRect = pointer to alternate rectangle in local coordinates.
  63.             index = index in kDynamicWindowStringsResourceID STR# resource of 
  64.                 help string.
  65. ----------------------------------------------------------------------------*/
  66.  
  67. void ShowHelpBalloon (Point tip, Rect *alternateRect, short index)
  68. {
  69.     HMMessageRecord helpMsg;
  70.     Rect r;
  71.     
  72.     if (tip.h == 0 && tip.v == 0) {
  73.         tip.h = (alternateRect->left + alternateRect->right) >> 1;
  74.         tip.v = (alternateRect->top + alternateRect->bottom) >> 1;
  75.     }
  76.     LocalToGlobal(&tip);
  77.     r = *alternateRect;
  78.     LocalToGlobalRect(&r);
  79.     helpMsg.hmmHelpType = khmmStringRes;
  80.     helpMsg.u.hmmStringRes.hmmResID = kDynamicWindowStringsResourceID;
  81.     helpMsg.u.hmmStringRes.hmmIndex = index;
  82.     HMShowBalloon(&helpMsg, tip, &r, nil, 0, 1, kHMRegularWindow);
  83. }
  84.  
  85.  
  86.  
  87. /*----------------------------------------------------------------------------
  88.     DoSizeBoxAndVerticalScrollBarBalloons 
  89.     
  90.     Handle help balloons for the size box and vertical scroll bar in a
  91.     window.
  92.             
  93.     Entry:    wind = pointer to window.
  94.             where = current mouse location in local coordinates.
  95.     
  96.     Exit:    function result = true if help balloon drawn.
  97. ----------------------------------------------------------------------------*/
  98.  
  99. Boolean DoSizeBoxAndVerticalScrollBarBalloons (WindowPtr wind, Point where)
  100. {
  101.     Rect r;
  102.     Point tip = {0, 0};
  103.     TWindow **info;
  104.     ControlHandle vScroll;
  105.     
  106.     r = wind->portRect;
  107.     r.left = r.right - 15;
  108.     r.top = r.bottom - 15;
  109.     if (PtInRect(where, &r)) {
  110.         ShowHelpBalloon(tip, &r, 1);
  111.         return true;
  112.     }
  113.     info = (TWindow**)GetWRefCon(wind);
  114.     vScroll = (**info).vScroll;
  115.     if (vScroll == nil) return false;
  116.     r = (**vScroll).contrlRect;
  117.     if (PtInRect(where, &r)) {
  118.         ShowHelpBalloon(tip, &r, (**vScroll).contrlMax > 0 ? 2 : 3);
  119.         return true;
  120.     }
  121.     return false;
  122. }
  123.  
  124.  
  125.  
  126. /*----------------------------------------------------------------------------
  127.     KillBalloon 
  128.         
  129.     Remove any help balloon which may be currently displayed on the screen.
  130. ----------------------------------------------------------------------------*/
  131.  
  132. void KillBalloon (void)
  133. {
  134.     if (!gInBackground && HMGetBalloons() && HMIsBalloon()) HMRemoveBalloon();
  135. }
  136.  
  137.  
  138.  
  139. /*----------------------------------------------------------------------------
  140.     InitHelpMenu 
  141.         
  142.     Initialize the Help menu topics.
  143. ----------------------------------------------------------------------------*/
  144.  
  145. void InitHelpMenu (void)
  146. {
  147.     MenuHandle helpMenu;
  148.     OSErr err = noErr;
  149.     short i, theID;
  150.     Handle h;
  151.     ResType theType;
  152.     Str255 name;
  153.     
  154.     err = MyHMGetHelpMenuHandle(&helpMenu);
  155.     if (err != noErr) return;
  156.     gNumStandardHelpMenuItems = CountMItems(helpMenu);
  157.     SetResLoad(false);
  158.     for (i = kFirstHelpMenuPictResourceID; ; i++) {
  159.         err = MyGet1Resource('PICT', i, &h);
  160.         if (err != noErr) break;
  161.         GetResInfo(h, &theID, &theType, name);
  162.         AppendMenu(helpMenu, name);
  163.     }
  164.     SetResLoad(true);
  165.     gNumHelpTopics = i - kFirstHelpMenuPictResourceID;
  166. }
  167.  
  168.  
  169.  
  170. /*----------------------------------------------------------------------------
  171.     AdjustHelpMenu 
  172.         
  173.     Adjust the Help menu (enable/disable our extra commands).
  174. ----------------------------------------------------------------------------*/
  175.  
  176. void AdjustHelpMenu (void)
  177. {
  178.     TWindowKind kind;
  179.     Boolean enabled;
  180.     short i;
  181.     MenuHandle helpMenu;
  182.     OSErr err = noErr;
  183.     
  184.     kind = GetMyWindowKind(FrontWindow());
  185.     enabled = kind != kDialog && !gLongOperation;
  186.     err = MyHMGetHelpMenuHandle(&helpMenu);
  187.     if (err != noErr) return;
  188.     for (i = 1; i <= gNumHelpTopics; i++) {
  189.         if (enabled) {
  190.             EnableItem(helpMenu, gNumStandardHelpMenuItems + i);
  191.         } else {
  192.             DisableItem(helpMenu, gNumStandardHelpMenuItems + i);
  193.         }
  194.     }
  195. }
  196.  
  197.  
  198.  
  199. /*----------------------------------------------------------------------------
  200.     CheckHelpWindowAlreadyOpen
  201.     
  202.     Check to see if a help window is already open, and if it is, bring it to
  203.     the front.
  204.     
  205.     Entry:    pictResID = 'PICT' resource id for window.
  206.                 
  207.     Exit:    function result = true if already open window brought to front.
  208. ----------------------------------------------------------------------------*/
  209.  
  210. static Boolean CheckHelpWindowAlreadyOpen (short pictResID)
  211. {
  212.     WindowPtr wind;
  213.     TWindowKind kind;
  214.     TWindow **info;
  215.     
  216.     wind = FrontWindow();
  217.     while (wind != nil) {
  218.         kind = GetMyWindowKind(wind);
  219.         if (kind == kHelp) {
  220.             info = (TWindow**)GetWRefCon(wind);
  221.             if (pictResID == (**info).pictResID) {
  222.                 MySelectWindow(wind);
  223.                 return true;
  224.             }
  225.         }
  226.         wind = (WindowPtr)(((WindowPeek)wind)->nextWindow);
  227.     }
  228.     return false;
  229. }
  230.  
  231.  
  232.  
  233. /*----------------------------------------------------------------------------
  234.     AdjustScrollMax
  235.         
  236.     Adjust the max scroll bar value.
  237.     
  238.     Entry:    wind = pointer to help window.
  239. ----------------------------------------------------------------------------*/
  240.  
  241. static void AdjustScrollMax (WindowPtr wind)
  242. {
  243.     TWindow **info;
  244.     PicHandle pict;
  245.     Rect picFrame;
  246.     ControlHandle vScroll;
  247.     short picHeight, viewHeight, pos, max;
  248.     
  249.     info = (TWindow**)GetWRefCon(wind);
  250.     pict = GetPicture((**info).pictResID);
  251.     picFrame = (**pict).picFrame;
  252.     vScroll = (**info).vScroll;
  253.     picHeight = picFrame.bottom - picFrame.top;
  254.     viewHeight = wind->portRect.bottom - 15 - 2*kTextMargin - kPanelHeight;
  255.     pos = GetControlValue(vScroll);
  256.     if (pos + viewHeight > picHeight) picHeight = pos + viewHeight;
  257.     max = picHeight - viewHeight;
  258.     if (max < 0) max = 0;
  259.     SetControlMaximum(vScroll, max);
  260. }
  261.  
  262.  
  263.  
  264. /*----------------------------------------------------------------------------
  265.     Scroll 
  266.     
  267.     Scroll a help window.
  268.  
  269.     Entry:    wind = pointer to help window.
  270.             dv = number of pixels to scroll.
  271.             
  272.     If the scroll bar's refCon is non-zero, the scroll bar max value is
  273.     adjusted after the scrolling operation. This is what you normally want.
  274.     The only exception is when scrolling in a TrackControl action procedure,
  275.     when you want to set the refCon to zero.
  276. ----------------------------------------------------------------------------*/
  277.  
  278. static void Scroll (WindowPtr wind, short dv)
  279. {
  280.     TWindow **info;
  281.     ControlHandle vScroll;
  282.     Rect r;
  283.     RgnHandle updateRgn;
  284.     
  285.     info = (TWindow**)GetWRefCon(wind);
  286.     vScroll = (**info).vScroll;
  287.     r = wind->portRect;
  288.     r.top += kPanelHeight;
  289.     r.right -= 15;
  290.     r.bottom -= 15;
  291.     InsetRect(&r, kTextMargin, kTextMargin);
  292.     updateRgn = NewRgn();
  293.     ScrollRect(&r, 0, dv, updateRgn);
  294.     InvalRgn(updateRgn);
  295.     DisposeRgn(updateRgn);
  296.     if (GetControlReference(vScroll) != 0) AdjustScrollMax(wind);
  297. }
  298.  
  299.  
  300.  
  301. /*----------------------------------------------------------------------------
  302.     ScrollByPartCode 
  303.     
  304.     Scroll a help window by part code.
  305.             
  306.     Entry:    wind = pointer to help window.
  307.             part = part code.
  308. ----------------------------------------------------------------------------*/
  309.  
  310. static void ScrollByPartCode (WindowPtr wind, short part)
  311. {
  312.     TWindow **info;
  313.     ControlHandle vScroll;
  314.     short val, max, page, dv;
  315.  
  316.     info = (TWindow**)GetWRefCon(wind);
  317.     vScroll = (**info).vScroll;
  318.     page = wind->portRect.bottom - 15 - 2*kTextMargin - 15;
  319.     val = (**vScroll).contrlValue;
  320.     max = (**vScroll).contrlMax;
  321.     dv = 0;
  322.     switch (part) {
  323.         case inUpButton:
  324.             dv = 15;
  325.             break;
  326.         case inDownButton:
  327.             dv = -15;
  328.             break;
  329.         case inPageUp:
  330.             dv = page;
  331.             break;
  332.         case inPageDown:
  333.             dv = -page;
  334.             break;
  335.         case kScrollToHome:
  336.             dv = val;
  337.             break;
  338.         case kScrollToEnd:
  339.             dv = val - max;
  340.             break;
  341.     }
  342.     if (val - dv < 0) {
  343.         dv = val;
  344.     } else if (val - dv > max) {
  345.         dv = val - max;
  346.     }
  347.     if (dv != 0) {
  348.         Scroll(wind, dv);
  349.         AdjustScrollMax(wind);
  350.         SetControlValue(vScroll, val - dv);
  351.     }
  352. }
  353.  
  354.  
  355.  
  356. /*----------------------------------------------------------------------------
  357.     ScrollAction 
  358.     
  359.     Vertical scroll bar action proc.
  360.  
  361.     Entry:    vScroll = handle to vertical scroll bar control.
  362.             part = part code.
  363. ----------------------------------------------------------------------------*/
  364.  
  365. static pascal void ScrollAction (ControlHandle vScroll, short part)
  366. {
  367.     WindowPtr wind;
  368.     
  369.     wind = (**vScroll).contrlOwner;
  370.     ScrollByPartCode(wind, part);
  371.     HandleUpdate(wind);
  372. }
  373.  
  374.  
  375.  
  376. /*----------------------------------------------------------------------------
  377.     DoHelpMenuCommand 
  378.         
  379.     Do a Help menu command.
  380.     
  381.     Entry:    item = item number in Help menu.
  382.     
  383.     Exit:    function result = error code.
  384. ----------------------------------------------------------------------------*/
  385.  
  386. OSErr DoHelpMenuCommand (short item)
  387. {
  388.     short pictResID;
  389.     OSErr err = noErr;
  390.     PicHandle pict;
  391.     short theID;
  392.     ResType theType;
  393.     Str255 title;
  394.     WindowPtr wind;
  395.     TWindow **info;
  396.     Rect r, arrowRect, backwardHotRect, forwardHotRect;
  397.     ControlHandle vScroll;
  398.     GrafPtr port;
  399.     ArrowPairRef helpArrowPair;
  400.     
  401.     pictResID = item - gNumStandardHelpMenuItems + 
  402.         kFirstHelpMenuPictResourceID - 1;
  403.     if (CheckHelpWindowAlreadyOpen(pictResID)) return noErr;
  404.     pict = GetPicture(pictResID);
  405.     GetResInfo((Handle)pict, &theID, &theType, title);
  406.     GetPort(&port);
  407.     err = CreateNewWindow(kHelp, title, "\pGeneva", 12, &wind);
  408.     if (err != noErr) return err;
  409.     SetPort(wind);
  410.     info = (TWindow**)GetWRefCon(wind);
  411.     (**info).pictResID = pictResID;
  412.     PositionNewWindow(wind, kMinWindowWidth, kMinWindowHeight);
  413.     SetRect(&r, kMinWindowWidth-15, kPanelHeight-1, kMinWindowWidth+1, kMinWindowHeight-14); 
  414.     vScroll = NewControl(wind, &r, "\p", true, 0, 0, 0, scrollBarProc, 1);
  415.     (**info).vScroll = vScroll;
  416.     SetRect(&arrowRect, 10, 5, 32, 15);
  417.     SetRect(&backwardHotRect, 8, 3, 20, 19);
  418.     SetRect(&forwardHotRect, 24, 3, 35, 19);
  419.     err = CreateArrowPair(false, &arrowRect, &backwardHotRect, 
  420.         &forwardHotRect, &helpArrowPair);
  421.     if (err != noErr) goto exit;
  422.     (**info).helpArrowPair = helpArrowPair;
  423.     EnableOrDisableArrowPair(helpArrowPair, -1, 
  424.         pictResID > kFirstHelpMenuPictResourceID);
  425.     EnableOrDisableArrowPair(helpArrowPair, +1,
  426.         pictResID < kFirstHelpMenuPictResourceID + gNumHelpTopics - 1);
  427.     err = DoZoom(wind, inZoomOut);
  428.     if (err != noErr) goto exit;
  429.     AdjustScrollMax(wind);
  430.     MyShowWindow(wind);
  431.     SetPort(port);
  432.     return noErr;
  433.     
  434. exit:
  435.  
  436.     DoClose(wind);
  437.     SetPort(port);
  438.     return err;
  439. }
  440.  
  441.  
  442.  
  443. /*----------------------------------------------------------------------------
  444.     OpenFirstHelpTopicWindow 
  445.         
  446.     Open the first help topic window.
  447.     
  448.     Exit:    function result = error code.
  449. ----------------------------------------------------------------------------*/
  450.  
  451. OSErr OpenFirstHelpTopicWindow (void)
  452. {
  453.     return DoHelpMenuCommand(gNumStandardHelpMenuItems + 1);
  454. }
  455.  
  456.  
  457.  
  458. /*----------------------------------------------------------------------------
  459.     ChangeTopic 
  460.     
  461.     Go forward or backward one topic.
  462.             
  463.     Entry:    wind = pointer to help window.
  464.             dir = +1 to go foward one topic, -1 to go backward.
  465.             
  466.     Exit:    function result = error code.
  467. ----------------------------------------------------------------------------*/
  468.  
  469. static OSErr ChangeTopic (WindowPtr wind, short dir)
  470. {
  471.     TWindow **info;
  472.     ControlHandle vScroll;
  473.     short pictResID;
  474.     PicHandle pict;
  475.     short theID;
  476.     ResType theType;
  477.     Str255 name;
  478.     
  479.     info = (TWindow**)GetWRefCon(wind);
  480.     vScroll = (**info).vScroll;
  481.     pictResID = (**info).pictResID;
  482.     while (true) {
  483.         pictResID += dir;
  484.         if (pictResID < kFirstHelpMenuPictResourceID ||
  485.             pictResID >= kFirstHelpMenuPictResourceID + gNumHelpTopics) 
  486.         {
  487.             SysBeep(0);
  488.             return noErr;
  489.         }
  490.         pict = GetPicture(pictResID);
  491.         GetResInfo((Handle)pict, &theID, &theType, name);
  492.         if (name[1] != '-') break;
  493.     }
  494.     SetWTitle(wind, name);
  495.     SetControlValue(vScroll, 0);
  496.     (**info).pictResID = pictResID;
  497.     EraseRect(&wind->portRect);
  498.     EnableOrDisableArrowPair((**info).helpArrowPair, -1, 
  499.         pictResID > kFirstHelpMenuPictResourceID);
  500.     EnableOrDisableArrowPair((**info).helpArrowPair, +1,
  501.         pictResID < kFirstHelpMenuPictResourceID + gNumHelpTopics - 1);
  502.     DoZoom(wind, inZoomOut);
  503.     return noErr;
  504. }
  505.  
  506.  
  507.  
  508. /*----------------------------------------------------------------------------
  509.     ResizeContents 
  510.     
  511.     Adjust a help window's contents after a window size change (grow
  512.     or zoom).
  513.             
  514.     Entry:    wind = pointer to help window.
  515. ----------------------------------------------------------------------------*/
  516.  
  517. static void ResizeContents (WindowPtr wind)
  518. {
  519.     TWindow **info;
  520.     short width, height;
  521.     ControlHandle vScroll;
  522.     Rect r;
  523.  
  524.     info = (TWindow**)GetWRefCon(wind);
  525.     vScroll = (**info).vScroll;
  526.     width = wind->portRect.right;
  527.     height = wind->portRect.bottom;
  528.     
  529.     SetRect(&r, width-15, kPanelHeight-1, width+1, height-14);
  530.     (**vScroll).contrlRect = r;
  531.     AdjustScrollMax(wind);
  532.     
  533.     InvalRect(&wind->portRect);
  534. }
  535.  
  536.  
  537.  
  538. /*----------------------------------------------------------------------------
  539.     DoSave 
  540.     
  541.     Handle the "Save" command.
  542.             
  543.     Entry:    wind = pointer to help window.
  544.             modifiers = modifiers field from event record.
  545.     
  546.     Exit:    function result = error code.
  547. ----------------------------------------------------------------------------*/
  548.  
  549. static OSErr DoSave (WindowPtr wind, short modifiers)
  550. {
  551.     Str255 title;
  552.     Str31 fileName;
  553.     StandardFileReply reply;
  554.     Str255 prompt;
  555.     OSErr err = noErr;
  556.     TWindow **info;
  557.     short refNum = 0;
  558.     Boolean empty;
  559.     short pictResID;
  560.     char zeros[0x200];
  561.     long length;
  562.     PicHandle pict;
  563.  
  564.     GetWTitle(wind, title);
  565.     MakeLegalFileName(title, fileName);
  566.     GetPString(kStrSaveFileAsPrompt, prompt);
  567.     MyStandardPutFile(prompt, fileName, &reply, nil);
  568.     if (!reply.sfGood) return userCanceledErr;
  569.     info = (TWindow**)GetWRefCon(wind);
  570.     pictResID = (**info).pictResID;
  571.  
  572.     err = OpenDataForkWriteCreateIfMissing(&reply.sfFile, 'ttxt', 'PICT',
  573.         reply.sfScript, false, &refNum, &empty);
  574.     if (err != noErr) goto exit;
  575.     
  576.     memset(zeros, 0, sizeof(zeros));
  577.     length = sizeof(zeros);
  578.     err = FSWrite(refNum, &length, zeros);
  579.     if (err != noErr) goto exit;
  580.     
  581.     pict = GetPicture(pictResID);
  582.     MyHLock(pict);
  583.     length = MyGetHandleSize(pict);
  584.     err = FSWrite(refNum, &length, *pict);
  585.     MyHUnlock(pict);
  586.     if (err != noErr) goto exit;
  587.  
  588.     MyFSClose(refNum, nil);
  589.     return noErr;
  590.     
  591. exit:
  592.  
  593.     if (refNum != 0) MyFSClose(refNum, nil);
  594.     return err;
  595. }
  596.  
  597.  
  598.  
  599. /*----------------------------------------------------------------------------
  600.     DoSaveAs
  601.     
  602.     Handle the "Save As" command.
  603.             
  604.     Entry:    wind = pointer to help window.
  605.             modifiers = modifiers field from event record.
  606.     
  607.     Exit:    function result = error code.
  608. ----------------------------------------------------------------------------*/
  609.  
  610. static OSErr DoSaveAs (WindowPtr wind, short modifiers)
  611. {
  612.     return DoSave(wind, modifiers);
  613. }
  614.  
  615.  
  616.  
  617. /*----------------------------------------------------------------------------
  618.     DoPrint 
  619.     
  620.     Handle the "Print" command.
  621.             
  622.     Entry:    wind = pointer to help window.
  623.             modifiers = modifiers field from event record.
  624.             
  625.     Exit:    function result = error code.
  626. ----------------------------------------------------------------------------*/
  627.  
  628. static OSErr DoPrint (WindowPtr wind, short modifiers)
  629. {
  630.     TWindow **info;
  631.     CStr255 title;
  632.     OSErr err = noErr;
  633.     
  634.     err = StartPrint();
  635.     if (err != noErr) return err;
  636.     
  637.     err = DisplayStatusMessageNumber(kStrPrinting);
  638.     if (err != noErr) return err;
  639.     
  640.     info = (TWindow**)GetWRefCon(wind);
  641.     GetWTitle(wind, (StringPtr)title);
  642.     p2cstr((StringPtr)title);
  643.     return PrintPict ((**info).pictResID, title);
  644. }
  645.  
  646.  
  647.  
  648. /*----------------------------------------------------------------------------
  649.     Activate 
  650.     
  651.     Handle an activate event for a help window.
  652.             
  653.     Entry:    wind = pointer to help window.
  654.             act = true to activate, false to deactivate
  655. ----------------------------------------------------------------------------*/
  656.  
  657. static void Activate (WindowPtr wind, Boolean act)
  658. {
  659.     TWindow **info;
  660.     ControlHandle vScroll;
  661.     Rect r;
  662.  
  663.     info = (TWindow**)GetWRefCon(wind);
  664.     vScroll = (**info).vScroll;
  665.     if (act) {
  666.         ShowControl(vScroll);
  667.     } else {
  668.         HideControl(vScroll);
  669.     }
  670.     r = wind->portRect;
  671.     r.top = r.bottom - 15;
  672.     r.left = r.right - 15;
  673.     InvalRect(&r);
  674. }
  675.  
  676.  
  677.  
  678. /*----------------------------------------------------------------------------
  679.     Update 
  680.     
  681.     Handle an update event for a help window.
  682.             
  683.     Entry:    wind = pointer to help window.
  684. ----------------------------------------------------------------------------*/
  685.  
  686. static void Update (WindowPtr wind)
  687. {
  688.     TWindow **info;
  689.     PicHandle pict;
  690.     Rect dstRect, r;
  691.     short pos, windWidth;
  692.     ControlHandle vScroll;
  693.     
  694.     info = (TWindow**)GetWRefCon(wind);
  695.     vScroll = (**info).vScroll;
  696.     pos = GetControlValue(vScroll);
  697.     
  698.     r = wind->portRect;
  699.     r.top = kPanelHeight;
  700.     ClipRect(&r);
  701.     DrawGrowIcon(wind);
  702.     NoClip();
  703.     
  704.     UpdateControls(wind, wind->visRgn);
  705.     
  706.     windWidth = wind->portRect.right - wind->portRect.left;
  707.     MoveTo(0, kPanelHeight-3);
  708.     LineTo(windWidth, kPanelHeight-3);
  709.     MoveTo(0, kPanelHeight-1);
  710.     LineTo(windWidth, kPanelHeight-1);
  711.     
  712.     DrawArrowPair((**info).helpArrowPair);
  713.  
  714.     r = wind->portRect;
  715.     r.top = kPanelHeight;
  716.     r.bottom -= 15;
  717.     r.right -= 15;
  718.     InsetRect(&r, kTextMargin, kTextMargin);
  719.     ClipRect(&r);
  720.     
  721.     pict = GetPicture((**info).pictResID);
  722.     HNoPurge((Handle)pict);
  723.     dstRect = (**pict).picFrame;
  724.     OffsetRect(&dstRect, -dstRect.left + kTextMargin, 
  725.         -dstRect.top + kPanelHeight + kTextMargin - pos);
  726.     DrawPicture(pict, &dstRect);
  727.     HPurge((Handle)pict);
  728.     
  729.     NoClip();
  730. }
  731.  
  732.  
  733.  
  734. /*----------------------------------------------------------------------------
  735.     Mouse 
  736.     
  737.     Handle a mouse down event in the content area of a help window.
  738.             
  739.     Entry:    wind = pointer to text window.
  740.             where = location of mouse down in local coords.
  741.             modifiers = modifiers field from event record.
  742.             
  743.     Exit:    function result = error code.
  744. ----------------------------------------------------------------------------*/
  745.  
  746. static OSErr Mouse (WindowPtr wind, Point where, short modifiers)
  747. {
  748.     TWindow **info;
  749.     short part, oldVal, dv, arrowTrackResult;
  750.     ControlHandle control, vScroll;
  751.  
  752.     info = (TWindow**) GetWRefCon(wind);
  753.     vScroll = (**info).vScroll;
  754.     part = FindControl(where, wind, &control);
  755.     if (part != 0 && control == vScroll) {
  756.         if (part == inThumb) {
  757.             oldVal = GetControlValue(vScroll);
  758.             TrackControl(vScroll, where, nil);
  759.             dv = GetControlValue(vScroll) - oldVal;
  760.             if (dv != 0) Scroll(wind, -dv);
  761.         } else {
  762.             SetControlReference(vScroll, 0);
  763.             TrackControl(vScroll, where, gScrollActionUPP);
  764.             SetControlReference(vScroll, 1);
  765.             AdjustScrollMax(wind);
  766.         }
  767.      }
  768.      arrowTrackResult = TrackArrowPair((**info).helpArrowPair);
  769.      if (arrowTrackResult != 0) return ChangeTopic(wind, arrowTrackResult);
  770.      return noErr;
  771. }
  772.  
  773.  
  774.  
  775. /*----------------------------------------------------------------------------
  776.     Draggable
  777.     
  778.     Determine whether a mouse down event is on a draggable object in a 
  779.     help window.
  780.     
  781.     Entry:    wind = pointer to text window.
  782.             where = location of mouse down event, in local coordinates.
  783.             modifiers = modifiers field from event record.
  784.             
  785.     Exit:    function result = true if object is draggable.
  786. ----------------------------------------------------------------------------*/
  787.  
  788. static Boolean Draggable (WindowPtr wind, Point where, short modifiers)
  789. {
  790.     return false;
  791. }
  792.  
  793.  
  794.  
  795. /*----------------------------------------------------------------------------
  796.     Key 
  797.     
  798.     Handle a key down event for a help window.
  799.             
  800.     Entry:    wind = pointer to help window.
  801.             theChar = ASCII code of key.
  802.             theKey = keyboard code of key.
  803.             modifiers = modifiers field from event record.
  804.             
  805.     Exit:    function result = error code.
  806. ----------------------------------------------------------------------------*/
  807.  
  808. static OSErr Key (WindowPtr wind, unsigned char theChar, unsigned char theKey, 
  809.     short modifiers)
  810. {
  811.     TWindow **info;
  812.     TKeypadKey keypadKey;
  813.  
  814.     info = (TWindow**)GetWRefCon(wind);
  815.  
  816.     if (gPrefs.keypadShortcuts && IsKeypadKey(theChar, theKey, &keypadKey)) {
  817.         switch (keypadKey) {
  818.             case kKeypadStarKey:
  819.                 return DoClose(wind);
  820.             case kKeypad1Key:
  821.                 ScrollByPartCode(wind, kScrollToEnd);
  822.                 return noErr;
  823.             case kKeypad2Key:
  824.                 ScrollByPartCode(wind, inDownButton);
  825.                 return noErr;
  826.             case kKeypad3Key:
  827.                 ScrollByPartCode(wind, inPageDown);
  828.                 return noErr;
  829.             case kKeypad7Key:
  830.                 ScrollByPartCode(wind, kScrollToHome);
  831.                 return noErr;
  832.             case kKeypad8Key:
  833.                 ScrollByPartCode(wind, inUpButton);
  834.                 return noErr;
  835.             case kKeypad9Key:
  836.                 ScrollByPartCode(wind, inPageUp);
  837.                 return noErr;
  838.             default:
  839.                 SysBeep(0);
  840.                 return noErr;
  841.         }
  842.     }
  843.     
  844.     if (theChar == pageUpKey) {
  845.         ScrollByPartCode(wind, inPageUp);
  846.         return noErr;
  847.     }
  848.     if (theChar == pageDownKey) {
  849.         ScrollByPartCode(wind, inPageDown);
  850.         return noErr;
  851.     }
  852.     if (theChar == homeKey) {
  853.         ScrollByPartCode(wind, kScrollToHome);
  854.         return noErr;
  855.     }
  856.     if (theChar == endKey) {
  857.         ScrollByPartCode(wind, kScrollToEnd);
  858.         return noErr;
  859.     }
  860.     
  861.     if (theChar == leftArrow) {
  862.         /*FlashArrowPair((**info).helpArrowPair, -1) - tried this, didn't like it*/;
  863.         return ChangeTopic(wind, -1);
  864.     }
  865.     if (theChar == rightArrow) {
  866.         /*FlashArrowPair((**info).helpArrowPair, +1) - tried this, didn't like it*/;
  867.         return ChangeTopic(wind, +1);
  868.     }
  869.     
  870.     if (gPrefs.keyboardShortcuts) {
  871.     
  872.         if (theChar == ' ') {
  873.             ScrollByPartCode(wind, inPageDown);
  874.             return noErr;
  875.         }
  876.         
  877.         theChar = tolower(theChar);
  878.         
  879.         if (theChar == 'w') {
  880.             return DoClose(wind);
  881.         }
  882.         
  883.     }
  884.  
  885.     SysBeep(0);
  886.     
  887.     return noErr;
  888. }
  889.  
  890.  
  891.  
  892. /*----------------------------------------------------------------------------
  893.     Grow 
  894.     
  895.     Handle a mouse down event in the grow box of a help window.
  896.     
  897.     Entry:    wind = pointer to help window.
  898.             where = location of mouse down event, in global coordinates.
  899.             
  900.     Exit:    function result = error code.
  901. ----------------------------------------------------------------------------*/
  902.  
  903. static OSErr Grow (WindowPtr wind, Point where)
  904. {
  905.     Rect sizeRect;
  906.     long size;
  907.     short width, height;
  908.     
  909.     SetRect(&sizeRect, kMinWindowWidth, kMinWindowHeight, kMaxShort, kMaxShort);
  910.     size = GrowWindow(wind, where, &sizeRect);
  911.     
  912.     if (size  != 0) {
  913.         width = LoWord(size);
  914.         height = HiWord(size);
  915.         SizeWindow(wind, width, height, false);
  916.         ResizeContents(wind);
  917.     }
  918.     
  919.     return noErr;
  920. }
  921.  
  922.  
  923.  
  924. /*----------------------------------------------------------------------------
  925.     Zoom
  926.     
  927.     Zoom a help window.
  928.     
  929.     Entry:    wind = pointer to help window.
  930.             zoomDir = zoom direction = inZoomIn or inZoomOut.
  931.             
  932.     Exit:    function result = error code.
  933. ----------------------------------------------------------------------------*/
  934.  
  935. static OSErr Zoom (WindowPtr wind, short zoomDir)
  936. {
  937.     TWindow **info;
  938.     short width, height;
  939.     Rect zoomRect;    
  940.     WStateData **wState;
  941.     PicHandle pict;
  942.     Rect picFrame;
  943.  
  944.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  945.     
  946.     if (zoomDir == inZoomOut) {
  947.         info = (TWindow**)GetWRefCon(wind);
  948.         pict = GetPicture((**info).pictResID);
  949.         picFrame = (**pict).picFrame;
  950.         width = picFrame.right - picFrame.left + 15 + 2*kTextMargin;
  951.         if (width < kMinWindowWidth) width = kMinWindowWidth;
  952.         height = picFrame.bottom - picFrame.top + 15 + kPanelHeight + 2*kTextMargin;
  953.         if (height < kMinWindowHeight) height = kMinWindowHeight;
  954.         CalculateZoomRect(wind, width, height, &zoomRect, gPrefs.dontCoverFinderIcons);
  955.         (**wState).stdState = zoomRect;
  956.         if (WindRectEqualRect(wind, &zoomRect)) return noErr;
  957.     }
  958.     
  959.     EraseRect(&wind->portRect);
  960.     ZoomWindow(wind, zoomDir, false);
  961.     ResizeContents(wind);
  962.     return noErr;
  963. }
  964.  
  965.  
  966.  
  967. /*----------------------------------------------------------------------------
  968.     Command 
  969.     
  970.     Handle a command for a help window.
  971.             
  972.     Entry:    wind = pointer to help window.
  973.             menu = the menu.
  974.             item = the item.
  975.             modifiers = modifiers field from event record.
  976.     
  977.     Exit:    function result = error code.
  978. ----------------------------------------------------------------------------*/
  979.  
  980. static OSErr Command (WindowPtr wind, short menu, short item, short modifiers)
  981. {
  982.     OSErr err = noErr;
  983.  
  984.     switch (menu) {
  985.     
  986.         case kFileMenu:
  987.         
  988.             switch (item) {
  989.                 case kSaveItem:
  990.                     err = DoSave(wind, modifiers);
  991.                     break;
  992.                 case kSaveAsItem:
  993.                     err = DoSaveAs(wind, modifiers);
  994.                     break;
  995.                 case kPrintItem:
  996.                     err = DoPrint(wind, modifiers);
  997.                     break;
  998.             }
  999.             break;
  1000.      }
  1001.      
  1002.      return err;
  1003. }
  1004.  
  1005.  
  1006.  
  1007. /*----------------------------------------------------------------------------
  1008.     Close 
  1009.     
  1010.     Close a help window.
  1011.             
  1012.     Entry:    wind = pointer to help window.
  1013.     
  1014.     Exit:    function result = error code.
  1015. ----------------------------------------------------------------------------*/
  1016.  
  1017. static OSErr Close (WindowPtr wind)
  1018. {
  1019.     TWindow **info;
  1020.  
  1021.     info = (TWindow**)GetWRefCon(wind);
  1022.     DisposeArrowPair((**info).helpArrowPair);
  1023.     MyDisposeHandle(info);
  1024.     MyDisposeWindow(wind);
  1025.     return noErr;
  1026. }
  1027.  
  1028.  
  1029.  
  1030. /*----------------------------------------------------------------------------
  1031.     Idle 
  1032.     
  1033.     Handle idle time tasks for a help window.
  1034.             
  1035.     Entry:    wind = pointer to help window.
  1036.     
  1037.     Exit:    cursorRgn = cursor region for WaitNextEvent mouse moved events.
  1038. ----------------------------------------------------------------------------*/
  1039.  
  1040. static void Idle (WindowPtr wind, RgnHandle cursorRgn)
  1041. {
  1042.     unsigned long fileEnabled, specialEnabled;
  1043.  
  1044.     SetCursor(&qd.arrow);
  1045.     
  1046.     if (gStartupOK) {
  1047.         specialEnabled = kHelpSpecialEnabled;
  1048.         SetMenusTo(kAppleAllEnabled, kHelpFileEnabled, kHelpEditEnabled, 
  1049.             kHelpNewsEnabled, specialEnabled, kHelpWindEnabled);
  1050.     } else {
  1051.         fileEnabled = kHelpFileEnabled;
  1052.         fileEnabled &= ~(kNewGroupWindowMask | kOpenMask);
  1053.         SetMenusTo(kAppleAllEnabled, fileEnabled, kHelpEditEnabled,
  1054.             kStartupBadNewsEnabled, kStartupBadSpecialEnabled, kStartupBadWindEnabled);
  1055.     }
  1056. }
  1057.  
  1058.  
  1059.  
  1060. /*----------------------------------------------------------------------------
  1061.     Help 
  1062.     
  1063.     Handle help balloons for a help window.
  1064.             
  1065.     Entry:    wind = pointer to help window.
  1066.             where = current mouse location in local coordinates.
  1067. ----------------------------------------------------------------------------*/
  1068.  
  1069. static void Help (WindowPtr wind, Point where)
  1070. {
  1071.     TWindow **info;
  1072.     Rect r;
  1073.     Point tip = {0, 0};
  1074.     short result;
  1075.     Boolean enabled;
  1076.  
  1077.     if (DoSizeBoxAndVerticalScrollBarBalloons(wind, where)) return;
  1078.     info = (TWindow**)GetWRefCon(wind);
  1079.     result = TestArrowPairHotRect((**info).helpArrowPair, where, &r, &enabled);
  1080.     if (result != 0) {
  1081.         if (enabled) {
  1082.             ShowHelpBalloon(tip, &r, result == -1 ? 4 : 5);
  1083.         } else {
  1084.             ShowHelpBalloon(tip, &r, result == -1 ? 6 : 7);
  1085.         }
  1086.         return;
  1087.     }
  1088.     SetRect(&r, 0, kPanelHeight, 
  1089.         wind->portRect.right -15, wind->portRect.bottom - 15);
  1090.     if (PtInRect(where, &r)) {
  1091.         ShowHelpBalloon(where, &r, 24);
  1092.         return;
  1093.     }
  1094. }
  1095.  
  1096.  
  1097.  
  1098. /*----------------------------------------------------------------------------
  1099.     InitHelpDispatchTable 
  1100.     
  1101.     Initialize the dispatch table for help windows.
  1102. ----------------------------------------------------------------------------*/
  1103.  
  1104. void InitHelpDispatchTable (void)
  1105. {
  1106.     TDispatch *d;
  1107.     
  1108.     d = &gDispatch[kHelp];
  1109.     
  1110.     d->activate = Activate;
  1111.     d->update = Update;
  1112.     d->mouse = Mouse;
  1113.     d->draggable = Draggable;
  1114.     d->key = Key;
  1115.     d->grow = Grow;
  1116.     d->zoom = Zoom;
  1117.     d->command = Command;
  1118.     d->close = Close;
  1119.     d->idle = Idle;
  1120.     d->help = Help;
  1121.     
  1122.     gScrollActionUPP = NewControlActionProc(ScrollAction);
  1123. }
  1124.